<article id="wikiArticle">
<div></div>
<div> </div>
<div><strong>let</strong> 语句声明一个块级作用域的本地变量，并且可选的将其初始化为一个值。</div>
<h2 id="语法">语法</h2>
<pre><code class="language-javascript">let var1 [= value1] [, var2 [= value2]] [, ..., varN [= valueN]];</code></pre>
<h3 id="参数">参数</h3>
<dl>
<dt><code>var1</code>, <code>var2</code>, …, <code>varN</code></dt>
<dd>变量名。必须是合法的标识符。</dd>
<dt><code>value1</code>, <code>value2</code>, …, <code>valueN</code></dt>
<dd>变量的初始值。可以是任意合法的表达式。</dd>
</dl>
<h2 id="描述">描述</h2>
<p><strong><code>let</code></strong>允许你声明一个作用域被限制在块级中的变量、语句或者表达式。与<strong><code>var</code></strong>关键字不同的是，<code><strong>var</strong></code>声明的变量只能是全局或者整个函数块的。</p>
<p>点<a class="external" href="https://stackoverflow.com/questions/37916940/js-why-let-have-this-name" rel="noopener">这里</a>可以明白我们为什么选取“<strong>let</strong>”这个名字。</p>
<h3 id="作用域规则">作用域规则</h3>
<p><code><strong>let</strong></code>声明的变量只在其声明的块或子块中可用，这一点，与<code><strong>var</strong></code>相似。二者之间最主要的区别在于<code><strong>var</strong></code>声明的变量的作用域是整个封闭函数。</p>
<pre><code  class="language-javascript">function varTest() {
  var x = 1;
  if (true) {
    var x = 2;  // 同样的变量!
    console.log(x);  // 2
  }
  console.log(x);  // 2
}

function letTest() {
  let x = 1;
  if (true) {
    let x = 2;  // 不同的变量
    console.log(x);  // 2
  }
  console.log(x);  // 1
}</code></pre>
<h3 id="简化内部函数代码">简化内部函数代码</h3>
<p>当用到内部函数的时候，<code><strong>let</strong></code>会让你的代码更加简单。</p>
<pre><code class="language-js">var list = document.getElementById("list");

for (let i = 1; i &lt;= 5; i++) {
  var item = document.createElement("LI");
  item.appendChild(document.createTextNode("Item " + i));

  let j = i;
  item.onclick = function (ev) {
    console.log("Item " + j + " is clicked.");
  };
  list.appendChild(item);
}
</code></pre>
<p>上面这段代码的意图是创建5个li,点击不同的li能够打印出当前li的序号。如果不用<strong><code>let</code></strong>，而改用<code><strong>var</strong></code>的话，将总是打印出 <code>Item 5 is Clicked</code>，因为 j 是函数级变量，5个内部函数都指向了同一个 j ,而 j 最后一次赋值是5。用了<strong><code>let</code></strong>后，j 变成块级域（也就是花括号中的块，每进入一次花括号就生成了一个块级域）,所以 5 个内部函数指向了不同的 j 。</p>
<p>在程序或者函数的顶层，<code><strong>let</strong></code>并不会像<strong><code>var</code></strong>一样在全局对象上创造一个属性，比如</p>
<pre><code class="language-js">var x = 'global';
let y = 'global';
console.log(this.x); // "global"
console.log(this.y); // undefined
</code></pre>
<h3 id="模仿私有接口">模仿私有接口</h3>
<p>在处理<a href="https://developer.mozilla.org/en-US/docs/Glossary/Constructor">构造函数</a>的时候，可以通过<code><strong>let</strong></code>声明而不是闭包来创建私有接口。</p>
<pre><code  class="language-javascript">var SomeConstructor;

{
    let privateScope = {};

    SomeConstructor = function SomeConstructor () {
        this.someProperty = "foo";
        privateScope.hiddenProperty = "bar";
    }

    SomeConstructor.prototype.showPublic = function () {
        console.log(this.someProperty); // foo
    }

    SomeConstructor.prototype.showPrivate = function () {
        console.log(privateScope.hiddenProperty); // bar
    }

}

var myInstance = new SomeConstructor();

myInstance.showPublic();
myInstance.showPrivate();

console.log(privateScope.hiddenProperty); // error</code></pre>
<h3 id="let_的暂存死区与错误">let 的暂存死区与错误</h3>
<p>在(<s>同一个函数或</s>)同一个作用域中用let重复定义一个变量将引起 <code><a class="new" href="/zh-CN/docs/JavaScript/Reference/Global_Objects/TypeError" rel="nofollow" title="TypeError">TypeError</a></code>.</p>
<pre><code  class="language-javascript">if (x) {
  let foo;
  let foo; // TypeError thrown.
}
</code></pre>
<p>在 ECMAScript 2015 中，<strong>let </strong>绑定不受变量提升的约束，这意味着 <strong>let</strong> <strong> </strong>声明<strong>不会</strong>被提升到当前执行上下文的顶部。在块中的变量初始化之前，引用它将会导致 <a href="Reference/Global_Objects/ReferenceError">ReferenceError</a>（而使用 var 声明变量则恰恰相反，该变量的值是 undefined ）。这个变量处于从块开始到 <strong>let</strong> 初始化处理的”暂存死区“之中。</p>
<pre><code  class="language-javascript">function do_something() {
  console.log(bar); // undefined
  console.log(foo); // ReferenceError: foo is not defined
  var bar = 1;
  let foo = 2;
}</code></pre>
<p>在 <a class="new" href="/zh-CN/docs/JavaScript/Reference/Statements/switch" rel="nofollow" title="switch"><code>switch</code></a> 声明中你可能会遇到这样的错误，因为一个switch只有一个作用块。</p>
<pre><code  class="language-javascript">switch (x) {
  case 0:
    let foo;
    break;
    
  case 1:
    let foo; // SyntaxError for redeclaration.
    break;
}</code></pre>
<p>但是，需要指出，在case语句后面可以创建新的作用域块，形成新的词法环境，这样就不会产生上述重复声明（<code>redeclaration</code>）的语法错误。</p>
<pre><code  class="language-javascript">let x = 1;

switch(x) {
  case 0: {
    let foo;
    break;
  }  
  case 1: {
    let foo;
    break;
  }
}</code></pre>
<p><code><strong>let</strong></code>后跟一个函数传递的参数时将导致循环内部报错。</p>
<pre><code  class="language-javascript">function go(n){
  for (let n of n.a) { // ReferenceError: n is not defined
    console.log(n);
  }
}

go({a:[1,2,3]});
</code></pre>
<h3 id="循环定义中的let作用域"><font face="Consolas, Liberation Mono, Courier, monospace">循环定义中的let作用域</font></h3>
<p>循环体中是可以引用在for声明时用let定义的变量，尽管let不是出现在大括号之间.(注：该方法在 火狐 45.4.0 ,Centos7 下，报错 <span class="hasBreakSwitch objectBox objectBox-errorMessage"><span class="errorMessage">ReferenceError: can't access lexical declaration `i' before initialization</span></span>)</p>
<pre><code class="language-js">var i = 0;
for (let i = i; i &lt; 10; i++) {
  console.log(i);
}
</code></pre>
<div class="note">
<p>注：以上 let 声明的 i 将会变成 undefined；chrome 版本50.0.2661.102 (64-bit)；推荐以下写法：</p>
</div>
<pre>var i = 0; 
for (let l = i; l &lt; 10; l++) {  
　console.log(l); 
}</code></pre>
<h4 id="域作用规则">域作用规则</h4>
<pre class="eval">for (let <var>expr1</var>; <var>expr2</var>; <var>expr3</var>) <var>statement</var>
</code></pre>
<p>在这个例子中，<var>expr2</var>, <var>expr3</var>, 和 <var>statement</var> 都是包含在一个隐含域块中，其中也包含了 expr1.</p>
<h2 id="例子">例子</h2>
<h3 id="let_对比_var"><code>let</code>  对比 <code>var</code></h3>
<p>let的作用域是块，而var的作用域是函数</p>
<pre><code  class="language-javascript">var a = 5;
var b = 10;

if (a === 5) {
  let a = 4; // The scope is inside the if-block
  var b = 1; // The scope is inside the function

  console.log(a);  // 4
  console.log(b);  // 1
} 

console.log(a); // 5
console.log(b); // 1</code></pre>
<h3 id="let_在循环中"><code>let</code> 在循环中</h3>
<p>可以用 let 来代替 var ，在 for 定义块中使用块级变量.</p>
<pre><code  class="language-javascript">for (let i = 0; i &lt; 10; i++) {
  console.log(i); // 0, 1, 2, 3, 4 ... 9
}

console.log(i); // i is not defined</code></pre>
<h2 id="非标准的_let_扩展">非标准的 let 扩展</h2>
<h3 id="let块（let_block）"><code>let块<strong>（</strong></code><strong><code>let</code> block）</strong></h3>
<div class="warning">
<p>let blocks 在 Gecko 44 中已经废除（ <a class="external" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1167029" rel="noopener" title="FIXED: Remove SpiderMonkey support for let blocks">bug 1167029</a>） 。</p>
</div>
<p><strong><code>let块</code></strong>提供了一种在块的范围内获取变量的值，而不会影响块外面名字相同的变量的值的方法。</p>
<h4 id="语法_2">语法</h4>
<pre><code class="language-javascript">let (var1 [= value1] [, var2 [= value2]] [, ..., varN [= valueN]]) block;</code></pre>
<h4 id="描述_2">描述</h4>
<p>let 语句块为变量提供了局部作用域。它的作用是在单一代码块的词法范围内绑定零个或多个变量； 此外与普通语句块没有任何区别。需要特别注意的是， 在 <code>let </code>语句块内使用 var 声明的变量，它的作用域与在 let 语句块之外声明没有区别；这样的变量仍然具有函数作用域。在使用 <code>let</code> 语句块时，必须使用花括号，否则会导致语法错误。</p>
<h4 id="例子_2">例子</h4>
<pre><code class="language-js">var x = 5;
var y = 0;

let (x = x + 10, y = 12) {
  console.log(x + y); // 27
}

console.log(x + y); // 5
</code></pre>
<p>let 代码块的规则与 JavaScript 中其他类型的代码块相同。允许在块内通过 let 关键字声明局部变量。</p>
<h4 id="作用域规则_2">作用域规则</h4>
<p>使用 <code>let</code> 语句块绑定的变量，其作用域是 <code>let</code> 语句块本身，与任何其内部语句块的作用域一样，除非在这些内部语句块内又定义了同名的变量。</p>
<h3 id="let_表达式（_let_expression）"><code>let </code><strong>表达式（</strong> let expression）</h3>
<div class="warning">
<p><code>let</code> expression 在 Gecko 41 已经废除（<a class="external" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1023609" rel="noopener" title="FIXED: Remove SpiderMonkey support for let expressions">bug 1023609</a>）。</p>
</div>
<p><strong><code>let</code>表达式</strong> 可以将变量的作用域仅作用于一条语句。</p>
<h4 id="语法_3">语法</h4>
<pre><code class="language-javascript">let (var1 [= value1] [, var2 [= value2]] [, ..., varN [= valueN]]) expression;</code></pre>
<h4 id="例子_3">例子</h4>
<p>你可以在一条语句的范围中使用 <code>let</code> 关键字来设立变量：</p>
<pre><code  class="language-javascript">var a = 5;
let(a = 6) console.log(a); // 6
console.log(a); // 5</code></pre>
<h4 id="作用域规则_3">作用域规则</h4>
<p>给定一个 <code>let</code> 表达式：</p>
<pre class="eval">let (<var>decls</var>) <var>expr</var>
</code></pre>
<p>这里隐式创建了一个包围 <var>expr</var> 的语句块。</p>
<h2 id="规范">规范</h2>
<table class="standard-table">
<tbody>
<tr>
<th scope="col">Specification</th>
<th scope="col">Status</th>
<th scope="col">Comment</th>
</tr>
<tr>
<td><a class="external" href="https://www.ecma-international.org/ecma-262/6.0/#sec-let-and-const-declarations" hreflang="en" lang="en" rel="noopener">ECMAScript 2015 (6th Edition, ECMA-262)<br/><small lang="zh-CN">Let and Const Declarations</small></a></td>
<td><span class="spec-Standard">Standard</span></td>
<td>Initial definition. Does not specify let expressions or let blocks.</td>
</tr>
<tr>
<td><a class="external" href="https://tc39.github.io/ecma262/#sec-let-and-const-declarations" hreflang="en" lang="en" rel="noopener">ECMAScript Latest Draft (ECMA-262)<br/><small lang="zh-CN">Let and Const Declarations</small></a></td>
<td><span class="spec-Draft">Draft</span></td>
<td> </td>
</tr>
</tbody>
</table>
<h2 id="浏览器兼容性">浏览器兼容性</h2>
<p></p><div class="blockIndicator warning"><strong><a class="external" href="https://github.com/mdn/browser-compat-data" rel="noopener">We're converting our compatibility data into a machine-readable JSON format</a></strong>.
            This compatibility table still uses the old format,
            because we haven't yet converted the data it contains.
            <strong><a class="new" href="/zh-CN/docs/MDN/Contribute/Structures/Compatibility_tables" rel="nofollow">Find out how you can help!</a></strong></div>
<div class="htab">
<a id="AutoCompatibilityTable" name="AutoCompatibilityTable"></a>
<ul>
<li class="selected"><a>Desktop</a></li>
<li><a>Mobile</a></li>
</ul>
</div><p></p>
<div id="compat-desktop">
<table class="compat-table">
<tbody>
<tr>
<th>Feature</th>
<th>Chrome</th>
<th>Edge</th>
<th>Firefox (Gecko)</th>
<th>Internet Explorer</th>
<th>Opera</th>
<th>Safari</th>
</tr>
<tr>
<td>Basic support</td>
<td>41.0</td>
<td><span style="color: #888;" title="Please update this with the earliest version of support.">(Yes)</span></td>
<td><a href="/en-US/Firefox/Releases/44" title="Released on 2016-01-26.">44</a> (44)</td>
<td>11</td>
<td>17</td>
<td><span style="color: rgb(255, 153, 0);" title="Compatibility unknown; please update this.">?</span></td>
</tr>
<tr>
<td>Temporal dead zone</td>
<td><span style="color: rgb(255, 153, 0);" title="Compatibility unknown; please update this.">?</span></td>
<td><span style="color: #888;" title="Please update this with the earliest version of support.">(Yes)</span></td>
<td><a href="/en-US/Firefox/Releases/35" title="Released on 2015-01-13.">35</a> (35)</td>
<td><span style="color: rgb(255, 153, 0);" title="Compatibility unknown; please update this.">?</span></td>
<td><span style="color: rgb(255, 153, 0);" title="Compatibility unknown; please update this.">?</span></td>
<td><span style="color: rgb(255, 153, 0);" title="Compatibility unknown; please update this.">?</span></td>
</tr>
<tr>
<td><code>let</code> expression <span class="icon-only-inline" title="This API has not been standardized."><i class="icon-warning-sign"> </i></span></td>
<td><span style="color: #f00;">未实现</span></td>
<td><span style="color: #f00;">未实现</span></td>
<td><span style="color: #f00;">未实现</span></td>
<td><span style="color: #f00;">未实现</span></td>
<td><span style="color: #f00;">未实现</span></td>
<td><span style="color: #f00;">未实现</span></td>
</tr>
<tr>
<td><code>let</code> block <span class="icon-only-inline" title="This API has not been standardized."><i class="icon-warning-sign"> </i></span></td>
<td><span style="color: #f00;">未实现</span></td>
<td><span style="color: #f00;">未实现</span></td>
<td><span style="color: #f00;">未实现</span></td>
<td><span style="color: #f00;">未实现</span></td>
<td><span style="color: #f00;">未实现</span></td>
<td><span style="color: #f00;">未实现</span></td>
</tr>
</tbody>
</table>
</div>
<div id="compat-mobile">
<table class="compat-table">
<tbody>
<tr>
<th>Feature</th>
<th>Android</th>
<th>Chrome for Android</th>
<th>Firefox Mobile (Gecko)</th>
<th>IE Mobile</th>
<th>Opera Mobile</th>
<th>Safari Mobile</th>
</tr>
<tr>
<td>Basic support</td>
<td><span style="color: rgb(255, 153, 0);" title="Compatibility unknown; please update this.">?</span></td>
<td>41.0</td>
<td>44.0 (44)</td>
<td><span style="color: rgb(255, 153, 0);" title="Compatibility unknown; please update this.">?</span></td>
<td><span style="color: rgb(255, 153, 0);" title="Compatibility unknown; please update this.">?</span></td>
<td><span style="color: rgb(255, 153, 0);" title="Compatibility unknown; please update this.">?</span></td>
</tr>
<tr>
<td>Temporal dead zone</td>
<td><span style="color: rgb(255, 153, 0);" title="Compatibility unknown; please update this.">?</span></td>
<td><span style="color: rgb(255, 153, 0);" title="Compatibility unknown; please update this.">?</span></td>
<td>35.0 (35)</td>
<td><span style="color: rgb(255, 153, 0);" title="Compatibility unknown; please update this.">?</span></td>
<td><span style="color: rgb(255, 153, 0);" title="Compatibility unknown; please update this.">?</span></td>
<td><span style="color: rgb(255, 153, 0);" title="Compatibility unknown; please update this.">?</span></td>
</tr>
<tr>
<td><code>let</code> expression <span class="icon-only-inline" title="This API has not been standardized."><i class="icon-warning-sign"> </i></span></td>
<td><span style="color: #f00;">未实现</span></td>
<td><span style="color: #f00;">未实现</span></td>
<td><span style="color: #f00;">未实现</span></td>
<td><span style="color: #f00;">未实现</span></td>
<td><span style="color: #f00;">未实现</span></td>
<td><span style="color: #f00;">未实现</span></td>
</tr>
<tr>
<td><code>let</code> block <span class="icon-only-inline" title="This API has not been standardized."><i class="icon-warning-sign"> </i></span></td>
<td><span style="color: #f00;">未实现</span></td>
<td><span style="color: #f00;">未实现</span></td>
<td><span style="color: #f00;">未实现</span></td>
<td><span style="color: #f00;">未实现</span></td>
<td><span style="color: #f00;">未实现</span></td>
<td><span style="color: #f00;">未实现</span></td>
</tr>
</tbody>
</table>
</div>
<h2 id="Firefox-specific_notes">Firefox-specific notes</h2>
<ul>
<li>[1]: 只允许用在被<code>&lt;script type="application/javascript;version=1.7"&gt;</code> 包裹的代码块中 （或者更高的 版本version）。当心，无论如何， 作为一个非标准特性， 很有可能会打破其他浏览器的支持。 <a class="new" href="/zh-CN/docs/XUL" rel="nofollow" title="zh-CN/docs/XUL">XUL</a> 脚本标签实现这些特性不需要特殊的块。 请看 <a class="external" href="https://bugzilla.mozilla.org/show_bug.cgi?id=932517" rel="noopener" title="FIXED: Enable let without version=1.7+ in non-strict mode">bug 932517</a>和<a class="external" href="https://bugzilla.mozilla.org/show_bug.cgi?id=932517" rel="noopener" title="FIXED: Enable let without version=1.7+ in non-strict mode">bug 932517</a>。</li>
<li>ES6 compliance for <code>let</code> in SpIderMonkey is tracked in <a class="external" href="https://bugzilla.mozilla.org/show_bug.cgi?id=950547" rel="noopener" title="FIXED: Make let and const ES6-compatible">bug 950547</a> and non-standard extensions are going to be removed in the future <a class="external" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1023609" rel="noopener" title="FIXED: Remove SpiderMonkey support for let expressions">bug 1023609</a>.</li>
</ul>
<h2 id="相关链接">相关链接</h2>
<ul>
<li><a href="Reference/Statements/var"><code>var</code></a></li>
<li><a href="Reference/Statements/const"><code>const</code></a></li>
<li><a class="external" href="https://hacks.mozilla.org/2015/07/es6-in-depth-let-and-const/" rel="noopener">ES6 In Depth: <code>let</code> and <code>const</code></a></li>
<li><a class="external" href="https://blog.mozilla.org/addons/2015/10/14/breaking-changes-let-const-firefox-nightly-44/" rel="noopener">Breaking changes in <code>let</code> and <code>const</code> in Firefox 44.</a></li>
<li><a class="external" href="https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20%26%20closures/ch3.md" rel="noopener">You Don't Know JS: Scope &amp; Closures: Chapter 3: Function vs. Block Scope</a></li>
</ul>
</article>